package org.wiw.server;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import org.wiw.client.MapService;
import org.wiw.client.model.Person;
import org.wiw.client.model.Place;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class MapServiceImpl extends RemoteServiceServlet implements MapService {

	private static Logger logger = Logger.getLogger(MapServiceImpl.class.getName());
	
	public String greetServer(String input) {
		String serverInfo = getServletContext().getServerInfo();
		String userAgent = getThreadLocalRequest().getHeader("User-Agent");
		return "Hello, " + input + "!<br><br>I am running " + serverInfo
				+ ".<br><br>It looks like you are using:<br>" + userAgent;
	}
	
	public Person getCurrentUser() {
		final User user = UserServiceFactory.getUserService().getCurrentUser();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		org.wiw.server.model.Person person=null;
		try{
			Query query = pm.newQuery(org.wiw.server.model.Person.class);
			query.setFilter("email == emailParam");
			query.declareParameters("String emailParam");
			List<org.wiw.server.model.Person> result = (List<org.wiw.server.model.Person>)query.execute(user.getEmail());
			if(!result.isEmpty()){
				person =  result.get(0);
			}
		} catch (Exception e) {}
		
		try {
			if(person == null){
				person = new org.wiw.server.model.Person(user.getNickname(), user.getEmail(), "red");
				pm.makePersistent(person);
				logger.info("Welcome new user " + getCurrentUserDetails());
			}
		} finally {
			pm.close();
		}
		return createPerson(person);
	}

	public void updatePerson(long id, String color) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try{
			org.wiw.server.model.Person person = pm.getObjectById(org.wiw.server.model.Person.class, id);
			if(isPermittedOperation(person)){
				person.setColor(color);
				pm.makePersistent(person);
			}
			else{
				logger.warning("Attempt to update foreign place ("+id+") by " + getCurrentUserDetails());
			}
		} finally {
			pm.close();
		}
	}
	
	public Place addPlace(double latitude, double longitude, Person person, String when, String description) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		org.wiw.server.model.Person dbPerson = pm.getObjectById(org.wiw.server.model.Person.class, person.getId());
		org.wiw.server.model.Place place = new org.wiw.server.model.Place(latitude, longitude, dbPerson, when, description);
		place = pm.makePersistent(place);
		dbPerson.getPlaces().add(place);
		try {
			pm.makePersistent(dbPerson);
		} finally {
			pm.close();
		}
		return createPlace(place);
	}
	
	public void movePlace(String id, double latitude, double longitude) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		org.wiw.server.model.Place place = pm.getObjectById(org.wiw.server.model.Place.class, KeyFactory.stringToKey(id));
		if(isPermittedOperation(place.getPerson())){
			place.setLatitude(latitude);
			place.setLongitude(longitude);
			try{
				pm.makePersistent(place);
			} finally {
				pm.close();
			}
		}
		else{
			logger.warning("Attempt to update foreign place ("+id+") by " + getCurrentUserDetails());
		}
	}
	
	public void editPlace(String id, String when, String description) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		org.wiw.server.model.Place place = pm.getObjectById(org.wiw.server.model.Place.class, KeyFactory.stringToKey(id));
		if(isPermittedOperation(place.getPerson())){
			place.setWhen(when);
			place.setDescription(description);
			try{
				pm.makePersistent(place);
			} finally {
				pm.close();
			}
		}
		else{
			logger.warning("Attempt to update foreign place ("+id+") by " + getCurrentUserDetails());
		}
	}
	
	public void removePlace(String id) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		org.wiw.server.model.Place place = pm.getObjectById(org.wiw.server.model.Place.class, KeyFactory.stringToKey(id));
		if(isPermittedOperation(place.getPerson())){
			try{
				pm.deletePersistent(place);
			} finally {
				pm.close();
			}
		}
		else{
			logger.warning("Attempt to remove foreign place ("+id+") by " + getCurrentUserDetails());
		}
	}
	
	public List<Place> getAllPlaces() {
		List<Place>places = new LinkedList<Place>();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(org.wiw.server.model.Place.class);
		try {
			for(org.wiw.server.model.Place place : (List<org.wiw.server.model.Place>) query.execute()){
			    places.add(createPlace(place));
			}
		} finally {
		    query.closeAll();
		    pm.close();
		}
		return places;
	}
	
	private String getCurrentUserDetails(){
		User user = UserServiceFactory.getUserService().getCurrentUser();
		return user.getNickname() + "<" + user.getEmail() +">";
	}
		
	private boolean isPermittedOperation(org.wiw.server.model.Person person){
		User user = UserServiceFactory.getUserService().getCurrentUser();
		return person.getEmail().equals(user.getEmail());
	}

	private Person createPerson(org.wiw.server.model.Person person) {
		return new Person(person.getId(), person.getNickname(), person.getColor());
	}
	
	private Place createPlace(org.wiw.server.model.Place place) {
		return new Place(KeyFactory.keyToString(place.getId()), place.getLatitude(), place.getLongitude(), createPerson(place.getPerson()), place.getWhen(), place.getDescription());
	}
	
}
